/*
 * Copyright 2010,2011 Michael Nitsche
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.mnit.basis.fehler;

import java.awt.AWTException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.security.InvalidKeyException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.sql.SQLException;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.xml.stream.XMLStreamException;

import de.mnit.basis.daten.ArrayHilfe;
import de.mnit.basis.fehler.system.F_Programm;
import de.mnit.basis.fehler.system.F_Sys_Datei;
import de.mnit.basis.fehler.system.F_Sys_InOut;
import de.mnit.basis.fehler.system.F_Sys_Netzwerk;
import de.mnit.basis.fehler.system.F_Sys_Sicherheit;
import de.mnit.basis.sys.Ausgabe;
import de.mnit.basis.sys.datei.S_DS_Element;


/**
 * @author Michael Nitsche
 *
 * Programmierfehler
 *   Definition  : Fehler die aufgrund von Bugs jederzeit auftreten können, aber nicht sollten.
 *   Verarbeitung: Weiterreichen nach oben, bis spätestens in der Main eine zentrale Verarbeitung mit meist Abbruch erfolgt
 *   Beispiel    : Division durch 0;
 *
 * Systemfehler
 *   Definition  : Fehler die jederzeit durch System oder Umwelt auftreten können.
 *   Verarbeitung: Die möglichst nahe Verarbeitung wird durch throws erzwungen
 *   Beispiel    : Datei nicht vorhanden oder Netzwerkverbindung bricht ab
 *
 * Benutzerfehler (Noch sehr in der Schwebe, da alles meist zu Programmierfehlern führt)
 *   Definition  : Fehler die durch Benutzereingaben oder Benutzerinteraktionen auftreten
 *   Verarbeitung: Die möglichst nahe Verarbeitung wird durch throws erzwungen
 *   Beispiel    : Passwort falsch eingegeben
 */
public class Fehler {

	public static final String text_debug="Debug-Fehler";

	// Systemfehler
	public class datei      extends H_DateiSys   {}
	public class netz       extends H_Netz       {}
	public class db			extends H_DB	     {}

	// Programmierfehler
	public class objekt     extends H_Objekt     {}
	public class text       extends H_Text       {}
	public class zahl       extends H_Zahl       {}
	public class bool       extends H_Bool       {}
	public class sonstige   extends H_Sonstige   {}
	public class konstante  extends H_Konstant  {}
	public class liste      extends H_Liste      {}
	public class bereich    extends H_Array		 {}
	public class sicherheit	extends H_Sicherheit {}

	// Benutzerfehler
	public class benutzer	extends H_Benutzer   {}


	// TODO Umbenennen in 'schnell' oder 'einfach'
	public static F_Programm direkt(String notiz, Object... oa)		{ return F_Programm.neu(notiz, oa); }
	public static F_Programm da_ToDo()   							{ return F_Programm.neu("TODO"); }
	public static F_Programm debugFehler()   						{ return F_Programm.neu("Debug-Fehler"); }


	/** TODO Besser mit Abbruch-Parameter verwenden! **/
	public static RuntimeException zeig(Throwable t) {
		return zeig(t, true, null);
	}

	/** @deprecated Mit Abbruch-Parameter verwenden! **/
	public static RuntimeException zeig(Throwable t, String text) {
		return zeig(t, true, text);
	}

	public static RuntimeException zeig(Throwable t, boolean abbruch) {
		return zeig(t, abbruch, null);
	}

	public static RuntimeException zeig(Throwable t, boolean abbruch, String text) {
		Ausgabe.fehler(t,text);
		if(abbruch) System.exit(1);
		return null;
	}

	public static F_Programm weitergeben(F_Programm e, Object... notiz) {
		Fehler.objekt.wenn_Null(e);
		e.plusNotiz(notiz);
		throw e;
	}

	public static F_Programm weitergeben(F_Sys_InOut e, Object... notiz) throws F_Sys_InOut {
		Fehler.objekt.wenn_Null(e);
		e.plusNotiz(notiz);
		throw e;
	}

	// Java-Wrap - Programmierfehler

	// Frage: Alle nachfolgenden 'weitergeben' umbenennen in 'javaWrap' oder 'java'?
	public static F_Programm weitergeben(RuntimeException          e, Object... notiz)   { return iProgFehlerWeitergeben(e, notiz); }
	public static F_Programm weitergeben(InstantiationException    e, Object... notiz)   { return iProgFehlerWeitergeben(e, notiz); }
	public static F_Programm weitergeben(IllegalAccessException    e, Object... notiz)   { return iProgFehlerWeitergeben(e, notiz); }
	public static F_Programm weitergeben(InvocationTargetException e, Object... notiz)   { return iProgFehlerWeitergeben(e, notiz); }
	public static F_Programm weitergeben(SQLException              e, Object... notiz)   { return iProgFehlerWeitergeben(e, notiz); }
	public static F_Programm weitergeben(NoSuchPaddingException    e, Object... notiz)   { return iProgFehlerWeitergeben(e, notiz); }
	public static F_Programm weitergeben(NoSuchAlgorithmException  e, Object... notiz)   { return iProgFehlerWeitergeben(e, notiz); }
	public static F_Programm weitergeben(IllegalBlockSizeException e, Object... notiz)   { return iProgFehlerWeitergeben(e, notiz); }
	public static F_Programm weitergeben(KeyStoreException         e, Object... notiz)   { return iProgFehlerWeitergeben(e, notiz); }
	public static F_Programm weitergeben(NoSuchProviderException   e, Object... notiz)   { return iProgFehlerWeitergeben(e, notiz); }
	public static F_Programm weitergeben(InterruptedException      e, Object... notiz)   { return iProgFehlerWeitergeben(e, notiz); }
	public static F_Programm weitergeben(AWTException              e, Object... notiz)   { return iProgFehlerWeitergeben(e, notiz); }
	public static F_Programm weitergeben(NoSuchMethodException     e, Object... notiz)   { return iProgFehlerWeitergeben(e, notiz); }

	// Java-Wrap - Systemfehler / Umweltfehler

	public static F_Sys_InOut weitergeben(IOException e, Object notiz1     , Object... notiz2) 		throws F_Sys_InOut   { return F_Sys_InOut.neu("Java-InOut-Fehler",	iVerbinde(e, notiz1, notiz2)); }
	public static F_Sys_Datei weitergeben(IOException e, File datei        , Object... notiz2) 		throws F_Sys_Datei   { return F_Sys_Datei.neu("Java-Datei-Fehler", 	iVerbinde(e, datei , notiz2)); }
	public static F_Sys_Datei weitergeben(IOException e, S_DS_Element datei, Object... notiz2) 		throws F_Sys_Datei   { return F_Sys_Datei.neu("Java-Datei-Fehler", 	iVerbinde(e, datei , notiz2)); }
	public static F_Sys_Datei weitergeben(FileNotFoundException e, Object datei, Object... notiz2) 	throws F_Sys_Datei   { return F_Sys_Datei.neu("Java-Datei-Fehler", 	iVerbinde(e, datei , notiz2)); }

	public static F_Sys_Netzwerk weitergeben(SocketException        e, String netz, Object... notiz2) 	throws F_Sys_Netzwerk   { return F_Sys_Netzwerk.neu("Java-Netzwerk-Fehler", iVerbinde(e, netz , notiz2)); }
	public static F_Sys_Netzwerk weitergeben(SocketTimeoutException e, String netz, Object... notiz2) 	throws F_Sys_Netzwerk   { return F_Sys_Netzwerk.neu("Java-Netzwerk-Fehler", iVerbinde(e, netz , notiz2)); }
//	public static F_Sys_Netzwerk weitergeben(EmailException e, Object... notiz) 						throws F_Sys_Netzwerk   { return F_Sys_Netzwerk.neu("Java-Crypt-Fehler", 	iVerbinde(e, notiz)); }

	public static F_Sys_Sicherheit weitergeben(InvalidKeyException e, Object... notiz) throws F_Sys_Sicherheit   { return F_Sys_Sicherheit.neu("Java-Crypt-Fehler", iVerbinde(e, notiz)); }
	public static F_Sys_Sicherheit weitergeben(BadPaddingException e, Object... notiz) throws F_Sys_Sicherheit   { return F_Sys_Sicherheit.neu("Java-Crypt-Fehler", iVerbinde(e, notiz)); }

	public static F_Sys_InOut weitergeben(XMLStreamException    e, Object... notiz) 				throws F_Sys_InOut   { return F_Sys_InOut.neu("Java-Stream-Fehler", iVerbinde(e, notiz)); }


	// PROTECTED

	protected static Object[] iVerbinde(Exception e, Object[] notiz) {
		Fehler.objekt.wenn_Null(e, notiz);
		return ArrayHilfe.verbinden(Object.class, e, notiz);
	}

	// INTERN

	private static F_Programm iProgFehlerWeitergeben(Exception e, Object... notiz) {
		return F_Programm.neu("Java-Fehler", iVerbinde(e, notiz));
	}

	private static Object[] iVerbinde(Exception e, Object notiz1, Object[] notiz2) {
		Object[] notiz=iNotizen(notiz1, notiz2);
		return iVerbinde(e, notiz);
	}

	private static Object[] iNotizen(Object notiz1, Object[] notiz2) {
		Fehler.objekt.wenn_Null(notiz1, notiz2);
		return ArrayHilfe.verbinden(Object.class, notiz1, notiz2);
	}

}
